[AWS] ブラウザからダイレクトで S3 に画像をアップロードする
S3 にブラウザから直接ファイルをアップロードする方法について試してみました。
S3 には直接 POST でアップロード可能なので、HTML の Form を使ってアップロードを行います。
この際に、Policy と Signature というものが必要で、これらをアップロードしたファイルと同時に S3 に渡すことで、認証を行う仕組みになっています。
事前準備
- S3 バケットの作成
- 自身の AWS のアクセスキーとシークレットキーを手元に用意
Policy と Signature の作成
最初に Policy Document を作成し、S3 へダイレクトアップロードする際の制約を定めます。
Policy Document は以下のような形式です。
{"expiration": "2013-08-17T00:00:00Z", "conditions": [ {"bucket": "bucket-name"}, ["starts-with", "$key", "uploads/"], {"acl": "private"}, {"success_action_redirect": "http://localhost/success.html"}, ["starts-with", "$Content-Type", ""], ["content-length-range", 0, 1048576] ] }
JSON 形式で、バケット名、有効期限やアップロードのファイル最小、最大サイズ等を指定します。
key には uploads/ と指定しているので、対象の S3 のバケット内にマネージメントコンソールから uploads という名前で Create Folder しておきます。
acl は、アップロードするファイルのアクセス権限を指定します。以下の形式が指定可能です。
private | public-read | public-read-write | authenticated-read | bucket-owner-read | bucket-owner-full-control
success_action_redirect には、アップロードが成功したあとのリダイレクト先を指定します。
上記の Policy Document を HTML の Form 上では、Base64 エンコードしたものを指定します。
更にこれにAWSシークレットキーを使って、Signature を作成します。
その作成コードが以下です。Ruby で作成しています。
require 'base64' require 'openssl' require 'digest/sha1'
policy_document = < aws_secret_key に自分の AWSシークレットキーを指定してください 出力された policy と signature を後述の HTML のテンプレートに指定します。 以下が S3 に POST する HTML のテンプレートです。
この Ruby コードをコマンドラインから実行します。
$ ruby generate_signature.rb
policy: eyJleHBpcm......
signature: ngYf/QScF4......
HTML のテンプレート
<html>
<head>
<title>S3 POST Form</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<form action="https://bucket-name.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
<input type="hidden" name="key" value="uploads/${filename}">
<input type="hidden" name="AWSAccessKeyId" value="YOUR_AWS_ACCESS_KEY">
<input type="hidden" name="acl" value="private">
<input type="hidden" name="success_action_redirect" value="http://localhost/success.html">
<input type="hidden" name="policy" value="YOUR_POLICY_DOCUMENT_BASE64_ENCODED">
<input type="hidden" name="signature" value="YOUR_CALCULATED_SIGNATURE">
<input type="hidden" name="Content-Type" value="image/jpeg">
File to upload to S3:
<input name="file" type="file">
<br>
<input type="submit" value="Upload File to S3">
</form>
</body>
</html>
action の URL の bucket-name には自分のバケット名を指定してください。https を指定していますが、http でも可能です。
AWSAccessKeyId は、AWSのアクセスキーを指定してください。
key は、アップロードするファイル名を指定します。${filename} とすることで、選択したファイル名のまま S3 にアップロードされます。
acl や success_action_redirect は、前述の Policy Document の内容と合わせる必要があります。
policy と signature は上記で作成したものを指定します。
S3 に直接アップロード
HTMLの準備ができたら Apache のドキュメントルート等に置き、アクセスします。
ファイルを指定して、アップロード中…
アップロードが終わりました!
マネージメントコンソールから S3 を確認すると、アップロードされていますね!
まとめ
S3 の Post サポートは便利ですね。ファイルサイズや有効期限を上手に Policy で定めて活用すれば特定の人に限定して公開したりもできますし、 直接 S3 なので、サーバーサイドの負荷も心配する必要はないですね。